package kkd.common.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.channels.FileChannel;

import kkd.common.logger.LogWriter;

public class FileUtil {
	
	public static boolean mkdir(String dir){
		File f=new File(dir);
		if(!f.exists()){
			return f.mkdirs();
		}
		return true;
	}
	
	public interface FileUtilReader{
		void read(Object data);
	}
	/**
	 * 以字节为单位读取文件，常用于读二进制文件，如图片、声音、影像等文件。
	 */
	public static void readFileByBytes(String fileName) {
		File file = new File(fileName);
		InputStream in = null;
		try {
			System.out.println("以字节为单位读取文件内容，一次读一个字节：");
			// 一次读一个字节
			in = new FileInputStream(file);
			int tempbyte;
			while ((tempbyte = in.read()) != -1) {
				System.out.write(tempbyte);
			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
			return;
		}
		try {
			System.out.println("以字节为单位读取文件内容，一次读多个字节：");
			// 一次读多个字节
			byte[] tempbytes = new byte[100];
			int byteread = 0;
			in = new FileInputStream(fileName);
			showAvailableBytes(in);
			// 读入多个字节到字节数组中，byteread为一次读入的字节数
			while ((byteread = in.read(tempbytes)) != -1) {
				System.out.write(tempbytes, 0, byteread);
			}
		} catch (Exception e1) {
			e1.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e1) {
				}
			}
		}
	}

	/**
	 * 以字符为单位读取文件，常用于读文本，数字等类型的文件
	 */
	public static void readFileByChars(String fileName) {
		File file = new File(fileName);
		Reader reader = null;
		try {
			System.out.println("以字符为单位读取文件内容，一次读一个字节：");
			// 一次读一个字符
			reader = new InputStreamReader(new FileInputStream(file));
			int tempchar;
			while ((tempchar = reader.read()) != -1) {
				// 对于windows下，\r\n这两个字符在一起时，表示一个换行。
				// 但如果这两个字符分开显示时，会换两次行。
				// 因此，屏蔽掉\r，或者屏蔽\n。否则，将会多出很多空行。
				if (((char) tempchar) != '\r') {
					System.out.print((char) tempchar);
				}
			}
			reader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		try {
			System.out.println("以字符为单位读取文件内容，一次读多个字节：");
			// 一次读多个字符
			char[] tempchars = new char[30];
			int charread = 0;
			reader = new InputStreamReader(new FileInputStream(fileName));
			// 读入多个字符到字符数组中，charread为一次读取字符数
			while ((charread = reader.read(tempchars)) != -1) {
				// 同样屏蔽掉\r不显示
				if ((charread == tempchars.length)
						&& (tempchars[tempchars.length - 1] != '\r')) {
					System.out.print(tempchars);
				} else {
					for (int i = 0; i < charread; i++) {
						if (tempchars[i] == '\r') {
							continue;
						} else {
							System.out.print(tempchars[i]);
						}
					}
				}
			}

		} catch (Exception e1) {
			e1.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
				}
			}
		}
	}
	public static void readFileByLines(String fileName,FileUtilReader rd) {
		readFileByLines(fileName, rd, "UTF-8");
	}

	/**
	 * 以行为单位读取文件，常用于读面向行的格式化文件
	 */
	public static void readFileByLines(String fileName,FileUtilReader rd,String charset) {
		File file = new File(fileName);
		BufferedReader reader = null;
		try {
			//            System.out.println("以行为单位读取文件内容，一次读一整行：");
//			reader = new BufferedReader(new FileReader(file));
			FileInputStream in = new FileInputStream(file);
			reader = new BufferedReader(new InputStreamReader(in,charset));
			String tempString = null;
			int line = 1;
			// 一次读入一行，直到读入null为文件结束
			while ((tempString = reader.readLine()) != null) {
				rd.read(tempString);
				// 显示行号
				//                System.out.println("line " + line + ": " + tempString);
				line++;
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
				}
			}
		}
	}

	/**
	 * 随机读取文件内容
	 */
	public static void readFileByRandomAccess(String fileName) {
		RandomAccessFile randomFile = null;
		try {
//			StringBuilder sb=new StringBuilder();
			System.out.println("随机读取一段文件内容：");
			// 打开一个随机访问文件流，按只读方式
			randomFile = new RandomAccessFile(fileName, "r");
			// 文件长度，字节数
			long fileLength = randomFile.length();
			// 读文件的起始位置
			int beginIndex = (fileLength > 4) ? 4 : 0;
			// 将读文件的开始位置移到beginIndex位置。
			randomFile.seek(beginIndex);
			byte[] bytes = new byte[1024];
			int byteread = 0;
			// 一次读10个字节，如果文件内容不足10个字节，则读剩下的字节。
			// 将一次读取的字节数赋给byteread
			while ((byteread = randomFile.read(bytes)) != -1) {
//				System.out.write(bytes, 0, byteread);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (randomFile != null) {
				try {
					randomFile.close();
				} catch (IOException e1) {
				}
			}
		}
	}

	/**
	 * 显示输入流中还剩的字节数
	 */
	private static void showAvailableBytes(InputStream in) {
		try {
			System.out.println("当前字节输入流中的字节数为:" + in.available());
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	/**
	 * A方法追加文件：使用RandomAccessFile
	 */
	public static void appendMethodA(String fileName, String content) {
		try {
			// 打开一个随机访问文件流，按读写方式
			RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
			// 文件长度，字节数
			long fileLength = randomFile.length();
			//将写文件指针移到文件尾。
			randomFile.seek(fileLength);
			randomFile.writeBytes(content);
			randomFile.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	/**
	 * A方法追加文件：使用RandomAccessFile
	 */
	public static void appendMethodA(String fileName, byte[] b) {
		try {
			// 打开一个随机访问文件流，按读写方式
			RandomAccessFile randomFile = new RandomAccessFile(fileName, "rw");
			// 文件长度，字节数
			long fileLength = randomFile.length();
			//将写文件指针移到文件尾。
			randomFile.seek(fileLength);
			randomFile.write(b);
			randomFile.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public static void writeMethodB(String fileName, String content,boolean append) {
		try {
			//打开一个写文件器，构造函数中的第二个参数true表示以追加形式写文件
			FileWriter writer = new FileWriter(fileName, append);
			writer.write(content);
			writer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * B方法追加文件：使用FileWriter
	 */
	public static void appendMethodB(String fileName, String content) {
		writeMethodB(fileName, content, true);
	}

	/**
	 * 文件copy
	 * @param src
	 * @param dest
	 * @return
	 */
	public static boolean copy(File src, File dest){
		boolean result = false;
		try {
			if ((src != null) && (!src.getCanonicalPath().equals(dest.getCanonicalPath())))
			{
				result = copyInternal(src, dest, new byte[4096]);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 递归copy
	 * @param src
	 * @param dest
	 * @param buf
	 * @return
	 */
	public static boolean copyInternal(File src, File dest, byte[] buf)	{
		boolean result = true;

		String[] files = null;
		if (src.isDirectory()) {
			files = src.list();
			result = dest.mkdir();
		} else {
			files = new String[1];
			files[0] = "";
		}
		if (files == null) {
			files = new String[0];
		}
		for (int i = 0; (i < files.length) && (result); i++) {
			File fileSrc = new File(src, files[i]);
			File fileDest = new File(dest, files[i]);
			if (fileSrc.isDirectory()) {
				result = copyInternal(fileSrc, fileDest, buf);
			} else {
				FileInputStream is = null;
				FileOutputStream os = null;
				try {
					is = new FileInputStream(fileSrc);
					os = new FileOutputStream(fileDest);
					int len = 0;
					while (true) {
						len = is.read(buf);
						if (len == -1)
							break;
						os.write(buf, 0, len);
					}
				} catch (IOException e) {
					e.printStackTrace();
					result = false;
				} finally {
					if (is != null)
						try {
							is.close();
						}
					catch (IOException e) {
					}
					if (os != null)
						try {
							os.close();
						}
					catch (IOException e) {
					}
				}
			}
		}
		return result;
	}

	/**
	 * 删除目录
	 * @param dir
	 */
	public static  void deleteDir(File dir) {
		String[] files = dir.list();
		if (files == null) {
			files = new String[0];
		}
		for (int i = 0; i < files.length; i++) {
			File file = new File(dir, files[i]);
			if (file.isDirectory())
				deleteDir(file);
			else {
				file.delete();
			}
		}
		dir.delete();
	}

	/**
	 * 删除目录
	 * @param dir
	 */
	public static  boolean deleteFile(File file) {
		if(file!=null && file.exists()){
			return file.delete();
		}
		return false;
	}


	public static double getDiskPartitionSpaceUsedPercent(final String path) {
		if (null == path || path.isEmpty())
			return -1;

		try {
			File file = new File(path);
			if (!file.exists()) {
				boolean result = file.mkdirs();
				if (!result) {
				}
			}

			long totalSpace = file.getTotalSpace();
			long freeSpace = file.getFreeSpace();
			long usedSpace = totalSpace - freeSpace;
			if (totalSpace > 0) {
				return usedSpace / (double) totalSpace;
			}
		}
		catch (Exception e) {
			return -1;
		}

		return -1;
	}

	/**
	 *  安全的写文件
	 */
	 public static final void string2File(final String str, final String fileName) throws IOException {
		// 先写入临时文件
		String tmpFile = fileName + ".tmp";
		string2FileNotSafe(str, tmpFile);

		// 备份之前的文件
		String bakFile = fileName + ".bak";
		String prevContent = file2String(fileName);
		if (prevContent != null) {
			string2FileNotSafe(prevContent, bakFile);
		}

		// 删除正式文件
		File file = new File(fileName);
		file.delete();

		// 临时文件改为正式文件
		file = new File(tmpFile);
		file.renameTo(new File(fileName));
	 }


	 public static final void string2FileNotSafe(final String str, final String fileName) throws IOException {
		 File file = new File(fileName);
		 File fileParent = file.getParentFile();
		 if (fileParent != null) {
			 fileParent.mkdirs();
		 }
		 FileWriter fileWriter = null;

		 try {
			 fileWriter = new FileWriter(file);
			 fileWriter.write(str);
		 }
		 catch (IOException e) {
			 throw e;
		 }
		 finally {
			 if (fileWriter != null) {
				 try {
					 fileWriter.close();
				 }
				 catch (IOException e) {
					 throw e;
				 }
			 }
		 }
	 }


	 public static final String file2String(final String fileName) {
		 File file = new File(fileName);
		 return file2String(file);
	 }


	 public static final String file2String(final URL url) {
		 InputStream in = null;
		 try {
			 URLConnection urlConnection = url.openConnection();
			 urlConnection.setUseCaches(false);
			 in = urlConnection.getInputStream();
			 int len = in.available();
			 byte[] data = new byte[len];
			 in.read(data, 0, len);
			 return new String(data, "UTF-8");
		 }
		 catch (Exception e) {
		 }
		 finally {
			 if (null != in) {
				 try {
					 in.close();
				 }
				 catch (IOException e) {
				 }
			 }
		 }

		 return null;
	 }


	 public static final String file2String(final File file) {
		 if (file.exists()) {
			 char[] data = new char[(int) file.length()];
			 boolean result = false;

			 FileReader fileReader = null;
			 try {
				 fileReader = new FileReader(file);
				 int len = fileReader.read(data);
				 result = (len == data.length);
			 }
			 catch (IOException e) {
				 // e.printStackTrace();
			 }
			 finally {
				 if (fileReader != null) {
					 try {
						 fileReader.close();
					 }
					 catch (IOException e) {
						 e.printStackTrace();
					 }
				 }
			 }

			 if (result) {
				 String value = new String(data);
				 return value;
			 }
		 }
		 return null;
	 }

	 /**
	  * 获取文件大小
	  * @param f
	  * @return
	  */
	 public static Long getFileSize(File f) {
		FileChannel fc= null;  
	    try {  
	        if (f.exists() && f.isFile()){  
	            FileInputStream fis= new FileInputStream(f);
	            fc= fis.getChannel();
	            return fc.size();
	        }else{
	        	
	        }
	    } catch (FileNotFoundException e) {  
	    	e.printStackTrace();
	    } catch (IOException e) {  
	    	e.printStackTrace();
	    } finally {  
	        if (null!=fc){  
	            try{  
	                fc.close();  
	            }catch(IOException e){  
	            	e.printStackTrace();
	            }  
	        }   
	    }
	    return null;
	}
	 
	 /**
	  * url 转 file
	  * @param url
	  * @return
	  */
	 public static File urlToFile(URL url){
		 URI u;
		 try {
			 File f=new File(url.toURI());
			 return f;
		 } catch (Exception e) {
			 e.printStackTrace();
		 }
		 return null;
	 }
	 
	 public static void closeInputStream(InputStream inputStream){
		 try {
			 if(inputStream!=null){
				 inputStream.close();
			 }
		 } catch (IOException e) {
			 LogWriter.error("",e);
		 }
	 }
	 
	 public static void main(String[] args) {
	 }
}
